------------------------------------------------------------------------------
-- UI module
------------------------------------------------------------------------------

local ui = {
  fonts_dir = "assets/fonts",
  images_dir = "assets/images",
  sounds_dir = "assets/sounds",
  fonts_ext = ".otf",
  images_ext = ".png",
  max_width = 1920,
  max_height = 1080,
  grid_unit = 120,
  window_width = 1200,
  window_height = 675,
  assets = {
    images = {},
    fonts = {},
    sounds = {},
  },
}

ui.scale = ui.window_width / ui.max_width

ui.colors = {
  yellow = { 255, 245, 133 },
  blue = { 13, 78, 135, },
  teal70 = { 92, 141, 136 },
  teal60 = { 135, 176, 170 },
  teal50 = { 126, 191, 180 },
  teal30 = { 156, 215, 205 },
  teal20 = { 197, 229, 218 },
  teal10 = { 237, 251, 255 },
  -- Menu, die button and game outcome modal colors
  magenta = { 224, 86, 84 },
  green = { 36, 189, 73 },
  emerald = { 26, 115, 116 },
  -- Text color
  white = { 255, 255, 255 },
  -- Outcome overlay colors
  orange = { 248, 163, 0 },
  mint = { 154, 255, 206 },
}


------------------------------------------------------------------------------
-- Asset preloading and scaling
------------------------------------------------------------------------------

-- Initialise assets from a directory of assets files
function ui.init_assets(dir, asset_type)
  -- Get a list of files and load them into the assets table
  -- [TODO] The use of `ls` is probably not cross-platform compatible.
  local files_str = io.popen("ls " .. dir)
  -- Abort if no files found
  if files_str == nil then do return end end
  if asset_type == "images" then
    for f in string.gmatch(files_str:read("*a"), "%S+") do
      if string.find(f, ui.images_ext) ~= nil then
        ui.assets.images[string.gsub(f, ui.images_ext, "")] =
          love.graphics.newImage(dir .. "/" .. f)
      end
    end

  elseif asset_type == "fonts" then
    for f in string.gmatch(files_str:read("*a"), "%S+") do
      if string.find(f, ui.fonts_ext) ~= nil then
        ui.assets.fonts[string.gsub(f, ui.fonts_ext, "")] =
          love.graphics.newFont(dir .. "/" .. f)
      end
    end

  elseif asset_type == "sounds" then
    for f in string.gmatch(files_str:read("*a"), "%S+") do
      if string.find(f, ui.sounds_ext) ~= nil then
        ui.assets.fonts[string.gsub(f, ui.sounds_ext, "")] =
          love.sound.newDecoder(dir .. "/" .. f)
      end
    end

  end
end


-- Return an alpha-adjusted value of a rgba color
function ui.alpha(col, a)
  local color_mod = {}
  -- Support pre-defined rgb colors
  if type(col) == "string" then color_mod = ui.colors[col] end
  color_mod[4] = a
  -- Default to opacity of 1
  if a == nil then color_mod[4] = 1 end
  -- Convert a rgb color to LÖVE color range
  for c = 1, #color_mod do
    if color_mod[c] > 1 then
      color_mod[c] = color_mod[c] / 255
    end
  end
  return color_mod
end

-- Return the size in pixels relative to the grid unit
function ui.units(size)
  return math.floor(ui.grid_unit * size * ui.scale)
end


-- Return the coordinates to center an image
function ui.center_pos(img)
  local pos = {}
  pos[1] = math.floor(((ui.max_width / 2) - (ui.assets.images[img]:getWidth()
    / 2)) * ui.scale)
  pos[2] = math.floor(((ui.max_height / 2) - (ui.assets.images[img]:getHeight()
    / 2)) * ui.scale)
  return pos
end


-- Convert the original size of an image to the scaled size
function ui.get_size(img)
  return { math.floor(ui.assets.images[img]:getWidth() * ui.scale),
    math.floor(ui.assets.images[img]:getHeight() * ui.scale) }
end


-- Wrapper around love.graphics.draw with scale factor included
function ui.draw(img, x, y, rot)
  if rot == nil then rot = 0 end
  love.graphics.draw(ui.assets.images[img], math.floor(x), math.floor(y), rot,
    ui.scale, ui.scale)
end


-- Wrapper around love.graphics.font with the scale factor included
function ui.print(str, x, y, font, size, col, align, align_width)
  -- [TODO] How to change the font size of an already preloaded font face
  -- without re-initialising? The path is also probably not cross-platform
  -- compatible.
  love.graphics.setNewFont(ui.fonts_dir .. "/" .. font .. ui.fonts_ext,
    math.floor(size * ui.scale))
  -- Default color is white
  if col == nil then
    love.graphics.setColor(ui.alpha("white"))
  else
    love.graphics.setColor(ui.alpha(col))
  end
  if (align ~= nil) and (align_width ~= nil) then
    love.graphics.printf(str, math.floor(x), math.floor(y), align_width,
      align)
  else
    love.graphics.print(str, math.floor(x), math.floor(y))
  end
  love.graphics.setColor(1, 1, 1)
end


-- Tile an image over a rectangular area
function ui.tile(img, x, y, width, height)
  local pos = { x, y }
  for hi = 1, math.ceil(height / ui.assets.images[img]:getHeight()) do
    pos[1] = 0
    for wi = 1, math.ceil(width / ui.assets.images[img]:getWidth()) do
      ui.draw(img, pos[1], pos[2])
      pos[1] = pos[1] + ui.get_size(img)[1]
    end
    pos[2] = pos[2] + ui.get_size(img)[2]
  end
end


------------------------------------------------------------------------------
-- Scenes
------------------------------------------------------------------------------

-- Title screen background
function ui.draw_title_view()
  ui.tile("main-menu-bg-tile", 0, 0, ui.max_width, ui.max_height)
  ui.draw("main-menu-title", ui.units(0.5),
    ui.center_pos("main-menu-title")[2])
end


-- Title screen main menu
function ui.draw_title_menu()
  -- [TODO] Change color of the buttons and labels to yellow when they are
  -- pressed
  ui.draw("main-menu-new", ui.units(10.4), ui.center_pos("main-menu-new")[2])
  ui.print("new", ui.units(10.3), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-load", ui.units(11.3), ui.center_pos("main-menu-load")[2])
  ui.print("load", ui.units(11.4), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-help", ui.units(12.4), ui.center_pos("main-menu-help")[2])
  ui.print("help", ui.units(12.5), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-settings", ui.units(13.6),
    ui.center_pos("main-menu-settings")[2])
  ui.print("settings", ui.units(13.5), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-quit", ui.units(14.8), ui.center_pos("main-menu-quit")[2])
  ui.print("quit", ui.units(14.9), ui.units(5), "calcutta-regular", 26)
end


-- Title screen new player selection menu
function ui.draw_new_player_menu()
  -- [TODO] Show "main-menu-player-selected" when the player color button is
  -- pressed and transition to new game
  -- [TODO] Change back button color and label to yellow and show the title
  -- menu if the back button is pressed
  ui.print("play as", ui.units(11.6), ui.units(3.7), "calcutta-regular", 32)
  ui.draw("main-menu-player-yellow", ui.units(10.8),
    ui.center_pos("main-menu-player-yellow")[2])
  ui.print("summer", ui.units(10.7), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-player-blue", ui.units(12.5),
    ui.center_pos("main-menu-player-blue")[2])
  ui.print("winter", ui.units(12.5), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-back", ui.units(14.8), ui.center_pos("main-menu-back")[2])
  ui.print("back", ui.units(14.7), ui.units(5), "calcutta-regular", 26)
end


-- Game board
function ui.draw_game_view()
  ui.tile("board-tile", 0, 0, ui.max_width, ui.max_height)
end


-- Game board interactive elements
function ui.draw_game_view_ie()
  -- [TODO] Die tray changes between yellow and blue depending on the player
  -- turn
  local current_turn = 1
  local die_tray = "die-tray-blue"
  if current_turn == 1 then die_tray = "die-tray-yellow" end
  ui.draw(die_tray, ui.units(0.3), ui.units(0.3))

  -- [TODO] Update dice count indicator as dice get played in round 1
  local dice_yellow = 4
  local dice_blue = 4
  if dice_yellow >= 1 then
    local die_pos_x = ui.units(2.25)
    for d = 1, dice_yellow do
      ui.draw("dice-count-yellow", die_pos_x, ui.units(0.3))
      die_pos_x = die_pos_x + ui.get_size("dice-count-yellow")[1] +
        ui.units(0.1)
    end
  end
  if dice_blue >= 1 then
    die_pos_x = ui.units(2.25)
    for d = 1, dice_blue do
      ui.draw("dice-count-blue", die_pos_x, ui.units(0.57))
      die_pos_x = die_pos_x + ui.get_size("dice-count-blue")[1] + ui.units(0.1)
    end
  end

  -- [TODO] Hide modal if the arrow up button is pressed
  -- [TODO] Show game view main menu modal if menu button is pressed
  local story_modal_open = true
  if story_modal_open then
    -- Story modal
    love.graphics.setColor(ui.alpha("teal50", 0.8))
    love.graphics.rectangle("fill", ui.units(12), 0, ui.units(4), ui.units(9))
    love.graphics.setColor(1, 1, 1)
    -- Modal nav
    ui.draw("modal-arrow-up", ui.units(13.8), ui.units(0.4))
    ui.draw("modal-menu", ui.units(14.9), ui.units(0.3))
  else
    ui.draw("nav-arrow-down", ui.units(13.8), ui.units(0.4))
    ui.draw("nav-menu", ui.units(14.9), ui.units(0.3))
  end
end


function ui.draw_game_outcome(result, color)
  -- [TODO] Play again button starts a new game
  -- [TODO] Close the game outcome view when mouse is pressed outside of the
  -- modal
  -- [TODO] Main menu button transitions to the game view main menu
  -- [TODO] Replace placeholder modal message
  -- Draw, blue has last move
  local overlay_col = "orange"
  local modal_img = "modal-outcome-draw-blue"
  local modal_pos_y = ui.center_pos(modal_img)[2] - ui.units(0.3)
  local modal_title = "Autumn has arrived"
  local modal_msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
    .. " sed do eiusmod tempor incididunt ut labore."
  -- Win, yellow
  if result == 1 and color == 1 then
    overlay_col = "yellow"
    modal_img = "modal-outcome-yellow"
    modal_pos_y = ui.center_pos(modal_img)[2] - ui.units(0.5)
    modal_title = "Summer has arrived"
  -- Win, blue
  elseif result == 1 and color == 0 then
    overlay_col = "blue"
    modal_img = "modal-outcome-blue"
    modal_title = "Winter has arrived"
  -- Draw, yellow has last move
  elseif result == 0 and color == 1 then
    overlay_col = "mint"
    modal_img = "modal-outcome-draw-yellow"
    modal_title = "Spring has arrived"
  end
  -- Overlay
  love.graphics.setColor(ui.alpha(overlay_col, 0.5))
  love.graphics.rectangle("fill", 0, 0, ui.units(16), ui.units(9))
  love.graphics.setColor(1, 1, 1)
  -- Main menu nav button
  ui.draw("nav-menu", ui.units(14.9), ui.units(0.3))
  -- Modal
  ui.draw(modal_img, ui.center_pos(modal_img)[1], modal_pos_y)
  ui.print(modal_title, ui.units(6), ui.units(4), "calcutta-bold", 52,
    "emerald", "center", ui.units(4))
  ui.print(modal_msg, ui.units(5.5), ui.units(4.6), "calcutta-regular", 26,
    "emerald", "center", ui.units(5))
  ui.print("play again", ui.units(6), ui.units(5.2), "calcutta-semibold", 26,
    "magenta", "center", ui.units(4))
end


function ui.draw_game_main_menu()
  -- [TODO] Add same button interactions as the title screen main menu
  -- Translucent overlay
  love.graphics.setColor(ui.alpha("teal60", 0.5))
  love.graphics.rectangle("fill", 0, 0, ui.units(12), ui.units(9))
  love.graphics.setColor(1, 1, 1)
  -- Modal
  love.graphics.setColor(ui.alpha("teal60", 0.8))
  love.graphics.rectangle("fill", ui.units(12), 0, ui.units(4), ui.units(9))
  love.graphics.setColor(1, 1, 1)
  -- Menu buttons
  ui.draw("modal-menu", ui.units(14.9), ui.units(0.3))
  ui.draw("main-menu-new", ui.units(13.1), ui.units(2.3))
  ui.print("new", ui.units(13), ui.units(3), "calcutta-regular", 26)
  ui.draw("main-menu-load", ui.units(14.4), ui.units(2.3))
  ui.print("load", ui.units(14.48), ui.units(3), "calcutta-regular", 26)
  ui.draw("main-menu-help", ui.units(12.9), ui.units(4.3))
  ui.print("help", ui.units(13), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-settings", ui.units(14.4), ui.units(4.3))
  ui.print("settings", ui.units(14.3), ui.units(5), "calcutta-regular", 26)
  ui.draw("main-menu-quit", ui.units(13.7), ui.units(6.2))
  ui.print("quit", ui.units(13.8), ui.units(6.9), "calcutta-regular", 26)
end


function ui.draw_help_view()
  -- [TODO] Back button transitions to previous scene when pressed
  -- [TODO] About button transitions to the about view when pressed
  -- [TODO] Add gameplay instructions
  ui.tile("main-menu-bg-tile", 0, 0, ui.max_width, ui.max_height)
  -- View nav
  ui.draw("main-menu-help", ui.center_pos("main-menu-help")[1], ui.units(0.6))
  ui.print("how to play", ui.units(6), ui.units(1.5), "calcutta-regular", 52,
    "white", "center", ui.units(4))
  ui.draw("main-menu-about", ui.units(0.6), ui.units(0.6))
  ui.print("about", ui.units(0.63), ui.units(1.3), "calcutta-regular", 26)
  ui.draw("main-menu-back", ui.units(14.8), ui.units(0.6))
  ui.print("back", ui.units(14.75), ui.units(1.3), "calcutta-regular", 26)
end


function ui.draw_about_view()
  -- [TODO] Same button transitions as the help view
  -- [TODO] Replace app_version with the correct variable
  local app_version = 0.1
  ui.tile("main-menu-bg-tile", 0, 0, ui.max_width, ui.max_height)
  -- View nav
  ui.draw("main-menu-about", ui.center_pos("main-menu-about")[1],
    ui.units(0.6))
  ui.print("about", ui.units(6), ui.units(1.4), "calcutta-regular", 52,
    "white", "center", ui.units(4))
  ui.draw("main-menu-help", ui.units(0.6), ui.units(0.6))
  ui.print("help", ui.units(0.7), ui.units(1.3), "calcutta-regular", 26)
  ui.draw("main-menu-back", ui.units(14.8), ui.units(0.6))
  ui.print("back", ui.units(14.75), ui.units(1.3), "calcutta-regular", 26)
  -- View contents
  ui.print("mako " .. tostring(app_version) .. " ©2022 43beans", ui.units(4),
    ui.units(2.3), "calcutta-regular", 30, "center", ui.units(8))
  ui.print("Credits", ui.units(4), ui.units(3.1), "calcutta-regular", 46,
    "white", "center", ui.units(8))
  ui.print("Story", ui.units(4), ui.units(3.8), "calcutta-bold",
    32, "white", "center", ui.units(8))
  ui.print("acdw", ui.units(4), ui.units(4.1), "calcutta-regular", 30,
    "white", "center", ui.units(8))
  ui.print("dozens", ui.units(4), ui.units(4.4), "calcutta-regular", 30,
    "white", "center", ui.units(8))
  ui.print("Art", ui.units(4), ui.units(5), "calcutta-bold", 32, "white",
    "center", ui.units(8))
  ui.print("mio", ui.units(4), ui.units(5.3), "calcutta-regular", 30,
    "white", "center", ui.units(8))
  ui.print("Sound", ui.units(4), ui.units(5.9), "calcutta-bold", 32,
    "white", "center", ui.units(8))
  ui.print("agafnd", ui.units(4), ui.units(6.2), "calcutta-regular", 30,
    "white", "center", ui.units(8))
  ui.print("Programming", ui.units(4), ui.units(6.8), "calcutta-bold", 32,
    "white", "center", ui.units(8))
  ui.print("marcus", ui.units(4), ui.units(7.1), "calcutta-regular", 30,
    "white", "center", ui.units(8))
  ui.print("wsinatra", ui.units(4), ui.units(7.4), "calcutta-regular", 30,
    "white", "center", ui.units(8))
end


function ui.draw_settings_view()
  -- [TODO] Back button transitions to previous scene when pressed
  ui.tile("main-menu-bg-tile", 0, 0, ui.max_width, ui.max_height)
  -- View nav
  ui.draw("main-menu-settings", ui.center_pos("main-menu-settings")[1],
    ui.units(0.6))
  ui.print("settings", ui.units(6), ui.units(1.4), "calcutta-regular", 52,
    "white", "center", ui.units(4))
  ui.draw("main-menu-back", ui.units(14.8), ui.units(0.6))
  ui.print("back", ui.units(14.75), ui.units(1.3), "calcutta-regular", 26)
  -- Settings
  ui.print("Music", ui.units(6.5), ui.units(2.7), "calcutta-regular", 40,
    "white", "left", ui.units(3.5))
  ui.draw("mode-cancel", ui.units(8), ui.units(2.74))
  ui.draw("mode-confirm", ui.units(8.7), ui.units(2.74))
  ui.print("Sfx", ui.units(6.5), ui.units(3.7), "calcutta-regular", 40,
    "white", "left", ui.units(3.5))
  ui.draw("mode-cancel", ui.units(8), ui.units(3.74))
  ui.draw("mode-confirm", ui.units(8.7), ui.units(3.74))
  ui.print("Dice", ui.units(6.5), ui.units(4.7), "calcutta-regular", 40,
    "white", "left", ui.units(3.5))
  love.graphics.draw(ui.assets.images["dice-1-4"], ui.units(8), ui.units(4.65),
    0, ui.scale * 0.5, ui.scale * 0.5)
  love.graphics.draw(ui.assets.images["dice-2-4"], ui.units(8.9),
    ui.units(4.65), 0, ui.scale * 0.5, ui.scale * 0.5)
end


------------------------------------------------------------------------------
-- Callback
------------------------------------------------------------------------------

function love.load()
  ui.init_assets(ui.images_dir, "images")
  ui.init_assets(ui.fonts_dir, "fonts")
  -- ui.init_assets(ui.sounds_dir, "sounds")
end


function love.draw()
  -- Title screen scene
  ui.draw_title_view()
  ui.draw_title_menu()
  -- ui.draw_new_player_menu()

  -- Game scene
  -- ui.draw_game_view()
  -- ui.draw_game_view_ie()

  -- Game outcome scenes
  -- ui.draw_game_outcome(1, 1)
  -- ui.draw_game_outcome(1, 0)
  -- ui.draw_game_outcome(0, 1)
  -- ui.draw_game_outcome(0, 0)

  -- Game scene main menu
  -- ui.draw_game_main_menu()

  -- Help, about and settings scenes
  -- ui.draw_help_view()
  -- ui.draw_about_view()
  -- ui.draw_settings_view()
end
